/*
 * Copyright (c) 2011, Marc-Andre Ferland - madrang@gmail.com
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the The Warrent Team nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *     * This software is free for non-commercial use. You may not use this
 *       software, in whole or in part, in support of any commercial product
 *       without the express consent of the author.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE WARRENT TEAM BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
using System;
using System.Runtime.InteropServices;

namespace OsHelper.UsbNet.Descriptors
{
	/// <summary>
	/// A structure representing the standard USB endpoint descriptor. This
	/// descriptor is documented in section 9.6.3 of the USB 2.0 specification.
	/// </summary>
	[StructLayout(LayoutKind.Explicit, Pack = 1, Size = 7)]
	public class EndpointDescriptor
	{
		/// <summary>
		/// Total size of this structure in bytes.
		/// </summary>
		public static int Size {
			get { return Marshal.SizeOf(typeof (EndpointDescriptor)); }
		}
		
		[FieldOffsetAttribute(0)]
		private Descriptor BaseDesc;
		
		/// <summary>
		/// The address of the endpoint on the USB device
		/// </summary>
		/// <remarks>
		/// The address is encoded as follows:
		/// Bit [3, 0]: The endpoint number
		/// Bit [6, 4]: Reserved, reset to zero
		/// Bit 7: Direction, ignored for control endpoints
		/// OUT endpoint = 0
		/// IN endpoint = 1
		/// </remarks>
		[FieldOffsetAttribute(2)]
		public byte Address;
		
		/// <summary>
		/// Attributes which apply to the endpoint when it is configured using the ConfigurationValue.
		/// </summary>
		[FieldOffsetAttribute(3)]
		public EndpointAttributes Attributes;
		
		/// <summary>
		/// Maximum packet size this endpoint is capable of sending/receiving.
		/// </summary>
		[FieldOffsetAttribute(4)]
		public short MaxPacketSize;
		
		/// <summary>
		/// Interval for polling endpoint for data transfers.
		/// </summary>
		[FieldOffsetAttribute(6)]
		public byte Interval;
		
		public EndpointDescriptor () : base()
		{
			this.Length = (byte)EndpointDescriptor.Size;
			this.Type = new DescriptorType(StandardDescriptorSubType.Endpoint);
		}
		
		public static EndpointDescriptor FromBytes(byte[] Data)
		{
			if(Data == null)
				throw new ArgumentNullException("Data");
			
			if(Data.Length < EndpointDescriptor.Size)
				throw new ArgumentException();
			
			if(Data.Length == EndpointDescriptor.Size)
				return (EndpointDescriptor)OsHelper.Serialyser.RawDeserialize(Data, typeof(EndpointDescriptor));
		
			byte[] DescData = new byte[EndpointDescriptor.Size];
			Array.Copy(Data, 0, DescData, 0, EndpointDescriptor.Size);
			
			return (EndpointDescriptor)OsHelper.Serialyser.RawDeserialize(DescData, typeof(EndpointDescriptor));
		}
		
		public byte Length {
			get { return this.BaseDesc.Length; }
			private set { this.BaseDesc.Length = value; }
		}
		
		public UsbNet.Descriptors.DescriptorType Type {
			get { return this.BaseDesc.Type; }
			private set { this.BaseDesc.Type = value; }
		}
		
		public byte Number {
			get {
				return (byte)(7 & this.Address);
			}
		}
		
		public TransferDirection Direction {
			get {
				return (TransferDirection)(1 & (this.Address >> 7));
			}
		}
		
	}
}
